package com.zzyl.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.dto.ReservationDto;
import com.zzyl.entity.Member;
import com.zzyl.entity.Reservation;
import com.zzyl.entity.TimeSlotCount;
import com.zzyl.exception.BusinessException;
import com.zzyl.mapper.CustomerReservationMapper;
import com.zzyl.mapper.MemberMapper;
import com.zzyl.service.CustomerReservationService;
import com.zzyl.utils.DateTimeUtils;
import com.zzyl.utils.StringUtils;
import com.zzyl.utils.UserThreadLocal;
import com.zzyl.vo.ReservationVo;
import com.zzyl.vo.TimeSlotCountVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class CustomerReservationServiceImpl implements CustomerReservationService {

    private static final int MAX_COUNT = 5;

    @Autowired
    private CustomerReservationMapper customerReservationMapper;

    @Autowired
    private MemberMapper memberMapper;

    @Override
    public int getCancelledCount() {
        // 1. 获取当前用户ID
        Long userId = UserThreadLocal.getUserId();
        if (userId == null) {
            throw new BusinessException("用户未登录");
        }

        // 2. 根据用户ID查询用户信息（主要是name）
        Member member = memberMapper.selectById(userId);
        if (member == null) {
            throw new BusinessException("用户不存在");
        }

        String userName = member.getName();
        if (StringUtils.isEmpty(userName)) {
            throw new BusinessException("用户姓名为空");
        }
        // 2. 查询该用户的取消预约次数
        // status = 2 表示取消状态
        Integer count = customerReservationMapper.countByUserIdAndStatus(userName, 2);

        // 3. 返回结果（如果为null则返回0）
        return count != null ? count : 0;
    }

    @Override
    public List<TimeSlotCountVo> getCountByTime(Long timestamp) {

        // 获取当前时间的时间戳
        Long currentTimestamp = System.currentTimeMillis() / 1000;

        // 生成时间槽，间隔为30分钟，每个槽内有五个预约名额
        List<TimeSlotCount> timeSlots = generateTimeSlotsForDateRange(timestamp, 1); // 查询从当前时间开始的1天的时间段
        log.info(timeSlots.toString());

        // 查询大于 timestamp 的所有时间槽内，已被预约的次数
        List<TimeSlotCount> timeSlots1 = customerReservationMapper.findTimeAfterTimestamp(currentTimestamp);
        log.info(timeSlots1.toString());

        // 比较 timeSlots 和 timeSlots1，得到每个时间段内剩余的预约次数
        for (TimeSlotCount timeSlot : timeSlots) {
            // 如果当前时间槽早于当前时间，设置 count 为 0
            if (timeSlot.getTimeSlot() < currentTimestamp) {
                timeSlot.setCount(0);
            } else {
                // 查找相同时间段的已预约数量
                for (TimeSlotCount reservedSlot : timeSlots1) {
                    if (timeSlot.getTimeSlot().equals(reservedSlot.getTimeSlot())) {
                        // 计算剩余预约次数
                        timeSlot.setCount(MAX_COUNT - reservedSlot.getCount());
                        break;
                    }
                }
            }

        }
        log.info(timeSlots.toString());
        // 把List<TimeSlotCount> timeSlots写入到List<TimeSlotCountVo> timeSlotsVo
        List<TimeSlotCountVo> timeSlotsVo = new ArrayList<>();
        for (TimeSlotCount timeSlot : timeSlots) {
            // Convert TimeSlotCount to TimeSlotCountVo
            TimeSlotCountVo timeSlotCountVo = new TimeSlotCountVo();
            timeSlotCountVo.setTime(DateTimeUtils.timestampToString(timeSlot.getTimeSlot() * 1000)); // Format the time as needed
            timeSlotCountVo.setCount(timeSlot.getCount());
            timeSlotsVo.add(timeSlotCountVo);
        }
        log.info(timeSlotsVo.toString());
        return timeSlotsVo;
    }

    @Override
    public void addReservation(ReservationDto reservationDto) {
        log.info(">> addReservation事务开始");
        System.out.println(reservationDto);
        Reservation reservation = convertDtoToReservation(reservationDto);
        reservation.setStatus(0);
        System.out.println(reservation);
        // 获取当前时间戳
        Long currentTimestamp = Instant.now().getEpochSecond();
        // 获取要预约的时间戳
        Long timeStampReservation = DateTimeUtils.localDateTimeToTimestamp(reservation.getTime()) / 1000;

        // 同一手机号，一个时间段只可预约一次 -- 前端已实现该功能，此次多此一举
        Long userId = UserThreadLocal.getUserId();
        Member member = memberMapper.selectById(userId);
        String mobile = member.getPhone();
        List<Reservation> reservationMobiles = customerReservationMapper.getByMobile(mobile, currentTimestamp);
        for (Reservation reservationMobile : reservationMobiles) {
            if (reservationMobile.getTime().equals(reservation.getTime())) {
                if (reservationMobile.getStatus() != 2) {
                    throw new BusinessException("该时间段已有预约");
                }
            }
        }

        // 验证所预约的时间段是否还有预约名额
        // 使用缓存或数据库查询来验证所预约的时间段是否还有名额
        List<TimeSlotCountVo> timeSlotsVos = getCountByTime(timeStampReservation);

        // 查找对应的时间槽，检查是否有剩余名额
        for (TimeSlotCountVo timeSlotVo : timeSlotsVos) {
            if (timeSlotVo.getTime().equals(reservation.getTime())) {
                if (timeSlotVo.getCount() <= 0) {
                    // 如果没有剩余名额，则抛出异常或返回错误
                    throw new BusinessException("该时间段已无名额");
                }
            }
        }

        customerReservationMapper.insert(reservation);
        log.info("<< addReservation事务提交");
    }

    @Override
    public PageResponse<ReservationVo> getByPage(Integer status, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        // 应当只能返回自己相关的预约
        Long userId = UserThreadLocal.getUserId();
        Member member = memberMapper.selectById(userId);
        String name = member.getName();
        String mobile = member.getPhone();
        // 获取当前时间戳
        Long currentTimestamp = Instant.now().getEpochSecond();
        Page<Reservation> reservations = customerReservationMapper.selectByPage(status, name, mobile, currentTimestamp);
        return PageResponse.of(reservations, ReservationVo.class);
    }

    @Override
    public void cancelReservation(Long id) {
        customerReservationMapper.cancelReservation(id);
    }

    /**
     * 生成时间段（跨天处理）
     */
    private List<TimeSlotCount> generateTimeSlotsForDateRange(Long startTimestamp, int numberOfDays) {
        List<TimeSlotCount> timeSlots = new ArrayList<>();
        // 每个时间槽的长度为 30 分钟
        long interval = 30 * 60; // 30分钟的时间戳，单位秒

        // 计算每天的起始时间和结束时间
        long startOfDayTimestamp = startTimestamp + (8 * 60 * 60);  // 每天的 8:00:00 时间戳
        long endOfDayTimestamp = startTimestamp + (18 * 60 * 60) + (30 * 60);   // 每天的 18:30:00 时间戳

        // 从 startTimestamp 开始，生成指定天数的时间槽
        for (int day = 0; day < numberOfDays; day++) {
            long currentDayStartTimestamp = startOfDayTimestamp + day * 24 * 60 * 60;  // 当前天的 8:00:00 时间戳

            for (int i = 0; i < 21; i++) {  // 每天有 21 个 30 分钟的时间槽
                long timeSlotTimestamp = currentDayStartTimestamp + (i * interval);  // 每个时间槽的时间戳

                if (timeSlotTimestamp >= currentDayStartTimestamp && timeSlotTimestamp < endOfDayTimestamp) {
                    timeSlots.add(new TimeSlotCount(timeSlotTimestamp, MAX_COUNT));  // 每个时间槽有5个名额
                }
            }
        }
        return timeSlots;
    }

    private Reservation convertDtoToReservation(ReservationDto reservationDto) {
        Reservation reservation = new Reservation();
        BeanUtils.copyProperties(reservationDto, reservation);
        return reservation;
    }

}
